function factorial(n)
{
	if(n<=1) return 1;
	
	var ret = 1;
	for(var i=2;i<=n;++i)
		ret *= i;
	
	return ret;
}

var randMean = 0;
var randStdv = 0;

function seed_Gaussian() 
{
	return (Math.random()*2-1)+(Math.random()*2-1)+(Math.random()*2-1);
}

function seed_Rayleigh() 
{
	return Math.sqrt(Math.pow(seed_Gaussian(), 2) + Math.pow(seed_Gaussian(), 2));
}

function seed_Erlang(alpha, lamda) 
{
	if (alpha == null)
		alpha = 1;
	if (lamda == null)
		lamda = 1;
	
	alpha = Math.floor(alpha);
	
	var product = 1.0;
	for (i = 0; i < alpha; i++)
		product *= seed_Gaussian();

	// Subtract product from 1.0 to avoid Math.Log(0.0)
	return (-1.0 / lamda) * Math.log(1.0 - product);
}

function initGaussian(mean, stdv) 
{
	randMean = mean;
	randStdv = stdv;
}

function initRayleigh(a, b)
{
	randMean = a + Math.sqrt(Math.PI*b/4);
	randStdv = Math.sqrt(b*(4-Math.PI)) / 2;
}

function initErlang(a, b)
{
	randMean = 1.0 * b / a;
	randStdv = Math.sqrt(b) / a;
}

function initUniform(a, b)
{
	randMean = (a + b) / 2;
	randStdv = (b - a) / Math.sqrt(12);
}

function randDouble(range, seed) 
{
	if (range == null)
		range = 1;
	return Math.round((seed*randStdv+randMean)*range);
}

function pdfGaussian(z, mean, stdv)
{
	return 1 / (stdv * Math.sqrt(2*Math.PI)) * Math.exp(- ((z-mean)*(z-mean) / (2*stdv*stdv)) );
}


function pdfRayleigh(z, a, b)
{
	if (z < a)
		return 0;
	
	return (2/b)*(z-a)*Math.exp(-Math.pow(z-a,2)/b);
}

function pdfErlang(z, a, b)
{
	if (z < 0)
		return 0;
		
	return (Math.pow(a,b)*Math.pow(z, b-1)) / factorial(b-1) * Math.exp(-a*z) ;
}

function pdfExponential(z, a)
{
	if (z < 0)
		return 0;
		
	return a * Math.exp(-a*z);
}

function pdfUniform(z, a, b)
{
	if ( a<= z && z <=b)
		return 1 / (b-a);
	
	return 0;
}


function pdfImpulse(z, a, b)
{
	if (z == a)
		return 255 - a;
	if (z == b)
		return 255 - b;	
		
	return 0;
}
